package simple;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.lionsoul.jcseg.ISegment;
import org.lionsoul.jcseg.IWord;
import org.lionsoul.jcseg.analyzer.JcsegAnalyzer;
import org.lionsoul.jcseg.dic.ADictionary;
import org.lionsoul.jcseg.dic.DictionaryFactory;
import org.lionsoul.jcseg.extractor.impl.TextRankKeyphraseExtractor;
import org.lionsoul.jcseg.extractor.impl.TextRankKeywordsExtractor;
import org.lionsoul.jcseg.segmenter.SegmenterConfig;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.List;

/**
 * @author wenqiang
 * @date 2021年07月26日周一
 * @comment 说明
 * 1.支持自定义词库。在lexicon文件夹下，可以随便添加/删除/更改词库和词库内容，并且对词库进行了分类。
 * 2.支持词库多目录加载. 配置lexicon.path中使用';'隔开多个词库目录.
 * 3.词库分为简体/繁体/简繁体混合词库: 可以专门适用于简体切分, 繁体切分, 简繁体混合切分, 并且可以利用下面提到的同义词实现,简繁体的相互检索, Jcseg同时提供了词库两个简单的词库管理工具来进行简繁体的转换和词库的合并。
 * 4.中英文同义词追加/同义词匹配 + 中文词条拼音追加．词库整合了《现代汉语词典》和cc-cedict辞典中的词条，并且依据cc-cedict词典为词条标上了拼音，依据《中华同义词词典》为词条标上了同义词(尚未完成)。更改jcseg.properties配置文档可以在分词的时候加入拼音和同义词到分词结果中。
 * 5.中文数字和中文分数识别，例如："一百五十个人都来了，四十分之一的人。"中的"一百五十"和"四十分之一"。并且 Jcseg会自动将其转换为阿拉伯数字加入到分词结果中。如：150， 1/40。
 * 6.支持中英混合词和英中混合词的识别(维护词库可以识别任何一种组合)。例如：B超, x射线, 卡拉ok, 奇都ktv, 哆啦a梦。
 * 7.更好的英文支持，电子邮件，域名，小数，分数，百分数，字母和标点组合词（例如C++, c#）的识别。
 * 8.自定义切分保留标点. 例如: 保留&, 就可以识别k&r这种复杂词条。
 * 9.复杂英文切分结果的二次切分: 可以保留原组合，同时可以避免复杂切分带来的检索命中率下降的情况，例如QQ2013会被切分成: qq2013/ qq/ 2013, chenxin619315@gmail.com会被切分成: chenxin619315@gmail.com/ chenxin/ 619315/ gmail/ com。
 * 10.支持阿拉伯数字/小数/中文数字基本单字单位的识别，例如2012年，1.75米，38.6℃，五折，并且 Jcseg会将其转换为“5折”加入分词结果中。
 * 11.智能圆角半角, 英文大小写转换。
 * 12.特殊字母识别：例如：Ⅰ，Ⅱ；特殊数字识别：例如：①，⑩。
 * 13.配对标点内容提取：例如：最好的Java书《java编程思想》，‘畅想杯黑客技术大赛’，被《,‘,“,『标点标记的内容。(1.6.8版开始支持)。
 * 14.智能中文人名/外文翻译人名识别。中文人名识别正确率达94%以上。（中文人名可以维护lex-lname.lex，lex-dname-1.lex，lex-dname-2.lex来提高准确率），(引入规则和词性后会达到98%以上的识别正确率)。
 * 15.自动中英文停止词过滤功能（需要在jcseg.properties中开启该选项，lex-stopwords.lex为停止词词库）。
 * 16.词库更新自动加载功能, 开启一个守护线程定时的检测词库的更新并且加载（注意需要有对应词库目录下的的lex-autoload.todo文件的写入权限）。
 * 17.自动词性标注（目前基于词库）。
 * 18.自动实体的识别，默认支持：电子邮件，网址，大陆手机号码，地名，人名，货币等；词库中可以自定义各种实体并且再切分中返回。
 *
 * lex词库文件
 * Jcseg的词性对照：
 * 名词n、时间词t、处所词s、方位词f、数词m、量词q、区别词b、代词r、动词v、形容词a、
 * 状态词z、副词d、介词p、连词c、助词u、语气词y、叹词e、拟声词o、成语i、习惯用语l、
 * 简称j、前接成分h、后接成分k、语素g、非语素字x、标点符号w）外，从语料库应用的角度，
 * 增加了专有名词（人名nr、地名ns、机构名称nt、其他专有名词nz）。
 */
public class SimpleMain {

    static String getPath(Object o) {
        String path = o.getClass().getProtectionDomain()
                .getCodeSource().getLocation().getFile();
        File jarFile = new File(path);
        return jarFile.getParentFile().getAbsolutePath();
    }

    public static void main(String[] args) {

        try {


            //创建SegmenterConfig分词配置实例，自动查找加载jcseg.properties配置项来初始化
            SegmenterConfig config = new SegmenterConfig(false);
            config.setMaxLength(20);
            //config.setPollTime(60);                     //重新加载词库的时间
            //config.setICnName(false);                   //是否识别中文名称
            //config.setPPT_MAX_LENGTH(15);               //成对标点文字的最大长度
            //config.setMaxCnLnadron(1);                  //中文姓氏最长
            config.setClearStopwords(false);             //设置不过滤停止词
            config.setAppendCJKSyn(false);               //设置关闭同义词追加
            config.setKeepUnregWords(true);            //是否保留不识别的词条
            //config.setKeepPunctuations("@#%.&+");       //保留在标记中的标点集（不是标记的结尾）
            //config.setAppendCJKPinyin(false);           //是否附加条目的拼音
            //config.setAppendCJKSyn(false);              //是否加载和附加条目的同义词
            //config.setDELIMITER();                    //设置为默认值或空白将使用默认空白作为分隔符

            config.setEnWordSeg(false);                  //是否做英语分词 在激活此函数之前，jcseg.ensecondseg必须设置为true
            //config.setEnMaxLen(16);                    //英语最长单词
            //config.setEnSecondSeg(false);              //是否对复杂的英语单词进行二次切分
            //config.setEnSecondMinLen(1);               //二次要分段标记的最小长度

            config.setCnNumToArabic(false);              //是否将中文数字转换为阿拉伯数字
            config.setCnFactionToArabic(false);

            config.setLoadCJKPos(false);                 //是否加载词条的词性
            config.setLoadCJKPinyin(false);             //是否加载条目的拼音
            config.setLoadCJKSyn(false);                //是否加载条目的同义词
            config.setLoadEntity(false);                 //是否加载条目的实体


            //创建默认单例词库实现，并且按照config配置加载词库
            ADictionary dic = DictionaryFactory.createSingletonDictionary(config, false);
            String preffix = Thread.currentThread().getContextClassLoader().getResource("").getPath();
            dic.load(preffix + "lexicon/qyzz.lex");
            dic.load(preffix + "lexicon/qyzz2.lex");


            //依据给定的ADictionary和SegmenterConfig来创建ISegment
            //为了Api往后兼容，建议使用SegmentFactory来创建ISegment对象

            //简易模式：FMM算法，适合速度要求场合。
            //ISegment seg = ISegment.SIMPLE.factory.create(config, dic);
            //复杂模式：MMSEG四种过滤算法，具有较高的歧义去除，分词准确率达到了98.41%。
            //ISegment seg = ISegment.COMPLEX.factory.create(config, dic);
            //检测模式：只返回词库中已有的词条，很适合某些应用场合。
            ISegment seg = ISegment.DETECT.factory.create(config, dic);
            //检索模式：细粒度切分，专为检索而生，除了中文处理外（不具备中文的人名，数字识别等智能功能）其他与复杂模式一致（英文，组合词等）
            //ISegment seg = ISegment.MOST.factory.create(config, dic);
            //分隔符模式：按照给定的字符切分词条，默认是空格，特定场合的应用
            //ISegment seg = ISegment.DELIMITER.factory.create(config, dic);
            //NLP模式：继承自复杂模式，更改了数字，单位等词条的组合方式，增加电子邮件，大陆手机号码，网址，人名，地名，货币等以及无限种自定义实体的识别与返回。
            //ISegment seg = ISegment.NLP.factory.create(config, dic);
            //ISegment seg = ISegment.NGRAM.factory.create(config, dic);


            /*
            //备注：以下代码可以反复调用，seg为非线程安全
            //设置要被分词的文本
            String str = "研究生命起源";
            seg.reset(new StringReader(str));

            //获取分词结果
            IWord word = null;
            while ((word = seg.next()) != null) {
                System.out.println(word.getValue());
            }*/

            //2, 构建TextRankKeyphraseExtractor关键短语提取器
            //TextRankKeyphraseExtractor extractor = new TextRankKeyphraseExtractor(seg);
            //extractor.setMaxIterateNum(120);        //设置pagerank算法最大迭代词库，非必须，使用默认即可
            //extractor.setWindowSize(10);             //设置textRank窗口大小，非必须，使用默认即可
            //extractor.setKeywordsNum(5);           //设置最大返回的关键词个数，默认为10
            //extractor.setMaxWordsNum(10);            //设置最大短语词长，默认为5
            //List<String> keyphrases = extractor.getKeyphrase(new StringReader(str));

            TextRankKeywordsExtractor extractor = new TextRankKeywordsExtractor(seg);
            extractor.setMaxIterateNum(100);        //设置pagerank算法最大迭代次数，非必须，使用默认即可
            extractor.setWindowSize(5);             //设置textRank计算窗口大小，非必须，使用默认即可
            extractor.setKeywordsNum(10);           //设置最大返回的关键词个数，默认为10
            //extractor.setAutoFilter(true);

            //String str = "在一个爆破从业单位工作，使用等级是：城市园林绿化二级";
            //String str = "恭喜你好获得「中国水利协会灌溉企业等级甲贰级」「全国土地估价执业机构全国执业」房屋建筑施工图审查二类房地产估价机构";
            String str = "全国公共资源交易平台金塘甬丰小区一期项目发布时间：2021-07-2011:17信息来源：舟山市公共资源交易网原文链接地址金塘甬丰小区一期项目[招标公告]1.招标条件本招标项目金塘甬丰小区一期项目已由浙江舟山群岛新区金塘管理委员会经济发展局以定金发审批[2021]11号批准建设，项目业主为舟山市金塘城乡开发建设有限公司，建设资金来自自筹，项目出资比例为100%，招标人为舟山市金塘城乡开发建设有限公司。项目已具备招标条件，现对该项目施工进行公开招标。2.项目概况与招标范围2.1工程名称：金塘甬丰小区一期项目2.2工程地址：舟山市定海区金塘镇河平村2.3工程概况：本项目总建筑面积3753.63㎡，其中住宅建筑面积3569.62㎡，电信间12.69㎡，弱电间12.69㎡，有线电视交接间11.86㎡，柴油发电机房26.37㎡，水泵房26.71㎡，配电房42.69㎡，居家养老用房13.78㎡，物业用房27.01㎡，门卫10.21㎡，建筑结构形式为框架结构，最大建筑高度19.3米。2.4招标范围：本工程施工图范围内土建工程、室外附属工程、绿化工程、安装工程（水电、消防、室外照明、室外消防、弱电、充电桩）、电梯工程等。2.5招标控制价：1507.6345万元；工期要求：450日历天；质量要求：合格。3.投标人资格要求3.1企业营业执照：真实有效；3.2企业资质：具有建筑工程施工总承包叁级及以上资质的独立法人；3.3企业安全生产许可证书及企业主要负责人A证:企业安全生产许可证书真实有效；企业主要负责人（包括企业法定代表人、企业分管安全的副总经理）必须具有A类安全考核合格证书；企业分管安全生产的副总经理任职文件；3.4企业、项目负责人经营行为:未被相关行政执法部门依据相关规定取消一定期限内参与依法必须招标项目的投标资格。（评审基准日期尚在限制期限内）；3.5项目负责人资格:具有建筑工程二级及以上注册建造师资格；3.6项目负责人近二年承接的项目：提供《项目负责人二年内在建和已完工程情况表》，该表必须由项目负责人本人签字，且内容真实可靠；3.7项目负责人承接工程业务量:无在建项目,项目负责人原承担的合同项目中途变更为其他人的，在该合同项目未通过竣工验收前不得参加本工程建设项目的投标活动，否则资格审查将不予通过。竣工验收以有效的竣工验收资料为准，该项目所在地建设行政主管部门出具的证明文件也有效；3.8项目班子配备:项目班子成员必须配备齐全，其中项目负责人必须具有B类安全生产考核合格证书，项目安全员（安全员配备符合建质【2008】91号文件要求）必须有C类安全生产考核合格证书，施工员、质量员、材料员、资料员均应有职业培训合格证或有效的岗位培训考核合格证书，全体人员有本企业有效的社保证明（近3个月内任意1个月），退休人员应有有效的聘用合同和退休证（如有）。3.9诚信承诺：投标人和其法定代表人必须对投标过程的企业行为作出诚信承诺；3.10企业及项目负责人未被信用中国网（www.creditchina.gov.cn）列入失信被执行人名单；3.11企业法人及项目负责人在中国裁判文书网（http://wenshu.court.gov.cn）5年内无行贿犯罪记录；3.12本次招标不接受联合体投标。3.13其他：投标单位为舟山市外企业的，在中标备案前，应到舟山市行政服务中心住建窗口建立企业联系卡。4.招标文件的获取4.1投标人在下载招标文件前须自行登陆“舟山市公共资源交易网”（http://zsztb.zhoushan.gov.cn/zsztbweb/），进行网上注册后登录舟山市电子招投标平台，于2021年7月21日至2021年7月27日，自行下载招标文件、图纸、招标控制价等资料。（投标人注册相关事宜如有不明确之处请咨询软件公司，客服电话4009980000或者舟山电子招投标支持群384041593。已经注册或登记成功的单位不得重复注册）。4.2本项目招标文件的补充（答疑、澄清）文件以网上下载方式发放。投标人自行关注，招标人不再一一通知。5.投标文件的递交5.1请投标人在招标文件规定的投标文件网上上传的截止时间前，登录舟山市电子招投标平台，在线制作投标文件并加密上传，投标人应按投标须知的要求参加开标会议，对上传的投标文件进行解密。6.发布公告的媒介本次招标公告同时在舟山市公共资源交易网http://zsztb.zhoushan.gov.cn/zsztbweb/上发布。7.联系方式招标人：舟山市金塘城乡开发建设有限公司联系方式：傅凯杰15958076530招标代理机构：浙江天隆工程管理有限公司联系方式：周钰翔0580-826092818768037112";
            str = str.replaceAll("(\\s|[0-9])", "");
            List<String> keyphrases = extractor.getKeywords(new StringReader(str));
            //List<String> keyphrases = extractor.getKeywordsFromFile(file.getPath());


            if (keyphrases.isEmpty()) {
                System.err.println("没有截取到内容");
            } else {
                for (String s : keyphrases) {
                    System.err.println("-->" + s);
                }
            }

/*
            JcsegAnalyzer analyzer = new JcsegAnalyzer(ISegment.COMPLEX, config, dic);
            SegmenterConfig config1 = analyzer.getConfig();
            config1.setMaxLength(20);

            //String words = "中华人民共和国";
            String words = str;
            TokenStream stream = null;
            try {
                stream = analyzer.tokenStream("myfield", words);
                stream.reset();
                CharTermAttribute offsetAtt = stream.addAttribute(CharTermAttribute.class);
                while (stream.incrementToken()) {
                    System.out.println(offsetAtt.toString());
                }
                stream.end();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                try {
                    if (stream != null)
                        stream.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            */

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}
